/*
 * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package com.sun.jmx.mbeanserver;

import java.util.logging.Level;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.JMRuntimeException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.RuntimeOperationsException;

import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;

/**
 * This class is the MBean implementation of the MBeanServerDelegate.
 *
 * @since 1.5
 */
final class MBeanServerDelegateImpl
    extends MBeanServerDelegate
    implements DynamicMBean, MBeanRegistration {

  final private static String[] attributeNames = new String[]{
      "MBeanServerId",
      "SpecificationName",
      "SpecificationVersion",
      "SpecificationVendor",
      "ImplementationName",
      "ImplementationVersion",
      "ImplementationVendor"
  };

  private static final MBeanAttributeInfo[] attributeInfos =
      new MBeanAttributeInfo[]{
          new MBeanAttributeInfo("MBeanServerId", "java.lang.String",
              "The MBean server agent identification",
              true, false, false),
          new MBeanAttributeInfo("SpecificationName", "java.lang.String",
              "The full name of the JMX specification " +
                  "implemented by this product.",
              true, false, false),
          new MBeanAttributeInfo("SpecificationVersion", "java.lang.String",
              "The version of the JMX specification " +
                  "implemented by this product.",
              true, false, false),
          new MBeanAttributeInfo("SpecificationVendor", "java.lang.String",
              "The vendor of the JMX specification " +
                  "implemented by this product.",
              true, false, false),
          new MBeanAttributeInfo("ImplementationName", "java.lang.String",
              "The JMX implementation name " +
                  "(the name of this product)",
              true, false, false),
          new MBeanAttributeInfo("ImplementationVersion", "java.lang.String",
              "The JMX implementation version " +
                  "(the version of this product).",
              true, false, false),
          new MBeanAttributeInfo("ImplementationVendor", "java.lang.String",
              "the JMX implementation vendor " +
                  "(the vendor of this product).",
              true, false, false)
      };

  private final MBeanInfo delegateInfo;

  public MBeanServerDelegateImpl() {
    super();
    delegateInfo =
        new MBeanInfo("javax.management.MBeanServerDelegate",
            "Represents  the MBean server from the management " +
                "point of view.",
            MBeanServerDelegateImpl.attributeInfos, null,
            null, getNotificationInfo());
  }

  final public ObjectName preRegister(MBeanServer server, ObjectName name)
      throws java.lang.Exception {
    if (name == null) {
      return DELEGATE_NAME;
    } else {
      return name;
    }
  }

  final public void postRegister(Boolean registrationDone) {
  }

  final public void preDeregister()
      throws java.lang.Exception {
    throw new IllegalArgumentException(
        "The MBeanServerDelegate MBean cannot be unregistered");
  }

  final public void postDeregister() {
  }

  /**
   * Obtains the value of a specific attribute of the MBeanServerDelegate.
   *
   * @param attribute The name of the attribute to be retrieved
   * @return The value of the attribute retrieved.
   * @throws MBeanException Wraps a <CODE>java.lang.Exception</CODE> thrown by the MBean's getter.
   */
  public Object getAttribute(String attribute)
      throws AttributeNotFoundException,
      MBeanException, ReflectionException {
    try {
      // attribute must not be null
      //
      if (attribute == null) {
        throw new AttributeNotFoundException("null");
      }

      // Extract the requested attribute from file
      //
      if (attribute.equals("MBeanServerId")) {
        return getMBeanServerId();
      } else if (attribute.equals("SpecificationName")) {
        return getSpecificationName();
      } else if (attribute.equals("SpecificationVersion")) {
        return getSpecificationVersion();
      } else if (attribute.equals("SpecificationVendor")) {
        return getSpecificationVendor();
      } else if (attribute.equals("ImplementationName")) {
        return getImplementationName();
      } else if (attribute.equals("ImplementationVersion")) {
        return getImplementationVersion();
      } else if (attribute.equals("ImplementationVendor")) {
        return getImplementationVendor();
      }

      // Unknown attribute
      //
      else {
        throw new AttributeNotFoundException("null");
      }

    } catch (AttributeNotFoundException x) {
      throw x;
    } catch (JMRuntimeException j) {
      throw j;
    } catch (SecurityException s) {
      throw s;
    } catch (Exception x) {
      throw new MBeanException(x, "Failed to get " + attribute);
    }
  }

  /**
   * This method always fail since all MBeanServerDelegateMBean attributes
   * are read-only.
   *
   * @param attribute The identification of the attribute to be set and  the value it is to be set
   * to.
   */
  public void setAttribute(Attribute attribute)
      throws AttributeNotFoundException, InvalidAttributeValueException,
      MBeanException, ReflectionException {

    // Now we will always fail:
    // Either because the attribute is null or because it is not
    // accessible (or does not exist).
    //
    final String attname = (attribute == null ? null : attribute.getName());
    if (attname == null) {
      final RuntimeException r =
          new IllegalArgumentException("Attribute name cannot be null");
      throw new RuntimeOperationsException(r,
          "Exception occurred trying to invoke the setter on the MBean");
    }

    // This is a hack: we call getAttribute in order to generate an
    // AttributeNotFoundException if the attribute does not exist.
    //
    Object val = getAttribute(attname);

    // If we reach this point, we know that the requested attribute
    // exists. However, since all attributes are read-only, we throw
    // an AttributeNotFoundException.
    //
    throw new AttributeNotFoundException(attname + " not accessible");
  }

  /**
   * Makes it possible to get the values of several attributes of
   * the MBeanServerDelegate.
   *
   * @param attributes A list of the attributes to be retrieved.
   * @return The list of attributes retrieved.
   */
  public AttributeList getAttributes(String[] attributes) {
    // If attributes is null, the get all attributes.
    //
    final String[] attn = (attributes == null ? attributeNames : attributes);

    // Prepare the result list.
    //
    final int len = attn.length;
    final AttributeList list = new AttributeList(len);

    // Get each requested attribute.
    //
    for (int i = 0; i < len; i++) {
      try {
        final Attribute a =
            new Attribute(attn[i], getAttribute(attn[i]));
        list.add(a);
      } catch (Exception x) {
        // Skip the attribute that couldn't be obtained.
        //
        if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
          MBEANSERVER_LOGGER.logp(Level.FINEST,
              MBeanServerDelegateImpl.class.getName(),
              "getAttributes",
              "Attribute " + attn[i] + " not found");
        }
      }
    }

    // Finally return the result.
    //
    return list;
  }

  /**
   * This method always return an empty list since all
   * MBeanServerDelegateMBean attributes are read-only.
   *
   * @param attributes A list of attributes: The identification of the attributes to be set and  the
   * values they are to be set to.
   * @return The list of attributes that were set, with their new values. In fact, this method
   * always return an empty list since all MBeanServerDelegateMBean attributes are read-only.
   */
  public AttributeList setAttributes(AttributeList attributes) {
    return new AttributeList(0);
  }

  /**
   * Always fails since the MBeanServerDelegate MBean has no operation.
   *
   * @param actionName The name of the action to be invoked.
   * @param params An array containing the parameters to be set when the action is invoked.
   * @param signature An array containing the signature of the action.
   * @return The object returned by the action, which represents the result of invoking the action
   * on the MBean specified.
   * @throws MBeanException Wraps a <CODE>java.lang.Exception</CODE> thrown by the MBean's invoked
   * method.
   * @throws ReflectionException Wraps a <CODE>java.lang.Exception</CODE> thrown while trying to
   * invoke the method.
   */
  public Object invoke(String actionName, Object params[],
      String signature[])
      throws MBeanException, ReflectionException {
    // Check that operation name is not null.
    //
    if (actionName == null) {
      final RuntimeException r =
          new IllegalArgumentException("Operation name  cannot be null");
      throw new RuntimeOperationsException(r,
          "Exception occurred trying to invoke the operation on the MBean");
    }

    throw new ReflectionException(
        new NoSuchMethodException(actionName),
        "The operation with name " + actionName +
            " could not be found");
  }

  /**
   * Provides the MBeanInfo describing the MBeanServerDelegate.
   *
   * @return The MBeanInfo describing the MBeanServerDelegate.
   */
  public MBeanInfo getMBeanInfo() {
    return delegateInfo;
  }

}
